package com.cyanite.playlv2;

import com.cyanite.playlv2.widget.AddFollowsAdapter;
import com.cyanite.playlv2api.PlayLv2Api;
import com.cyanite.playlv2api.types.Group;
import com.cyanite.playlv2api.types.Response;
import com.cyanite.playlv2api.types.User;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.Toast;

import java.util.HashMap;
import java.util.LinkedHashMap;

/**
 * Presents all friends that i have and you can send invitation
 * to all of them to focus your new trip
 *
 */
public class AddFollowsActivity extends ListActivity{

    public static final String EXTRA_TRIP_ID = PlayLv2.PACKAGE_NAME
        + ".AddFollowsActivity.EXTRA_TRIP_ID";

    private EditText mNameFilter;
    private AddFollowsAdapter mListAdapter;
    private ProgressDialog mProgressDlg;
    private Handler mHandler;
    private StateHolder mStateHolder;
    private Button mBtnAddFriends;
    private Button mBtnAddAllFriends;
    private RelativeLayout mHead;

    private BroadcastReceiver mLoggedOutReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.add_follows_activity);
        registerReceiver(mLoggedOutReceiver, new IntentFilter(PlayLv2.INTENT_ACTION_LOGGED_OUT));
        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

        mStateHolder = new StateHolder();
        mStateHolder.setUserId(((PlayLv2) getApplication()).getUserId());
        if (getIntent().hasExtra(EXTRA_TRIP_ID)) {
            mStateHolder.setTripId(getIntent().getExtras().getString(EXTRA_TRIP_ID));
        }   else {
            finish();
            return;
        }

        startProgressBar(getResources().getString(R.string.add_follows_requests_activity_label),
                getResources().getString(R.string.add_follows_requests_progress_bar_loading));
        mStateHolder.startTaskFriendOnPlayLv2(this);

        ensureUi();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

     @Override
    public void onPause() {
        super.onPause();
        stopProgressBar();

        if (isFinishing()) {
            mListAdapter.removeObserver();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mLoggedOutReceiver);
    }

    private void ensureUi() {
        mHandler = new Handler();
        mHead = (RelativeLayout)findViewById(R.id.rlHead);
        mBtnAddAllFriends = (Button)findViewById(R.id.btnInviteAll);
        mBtnAddAllFriends.setVisibility(View.GONE);
        mBtnAddFriends = (Button)findViewById(R.id.btnAddFriends);
        mBtnAddFriends.setVisibility(View.GONE);
        mNameFilter = (EditText)findViewById(R.id.editTextFilter);
        mNameFilter.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Run the filter operation after a brief waiting period in case the user
                // is typing real fast.
                mHandler.removeCallbacks(mRunnableFilter);
                mHandler.postDelayed(mRunnableFilter, 700L);
            }
        });

        Button btnDone = (Button)findViewById(R.id.btnDone);
        btnDone.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

        mListAdapter = new AddFollowsAdapter(this, mButtonRowClickHandler,
                ((PlayLv2) getApplication()).getRemoteResourceManager());
        getListView().setAdapter(mListAdapter);
        getListView().setItemsCanFocus(true);
    }

    private void startProgressBar(String title, String message) {
        if (mProgressDlg == null) {
            mProgressDlg = ProgressDialog.show(this, title, message);
        }
        mProgressDlg.show();
    }

    private void stopProgressBar() {
        if (mProgressDlg != null) {
            mProgressDlg.dismiss();
            mProgressDlg = null;
        }
    }

    private void onFriendsOnPlayLv2TaskComplete(Group<User> users, HashMap<String, Group<User>> usersAlpha, Exception ex) {
        // Recreate the adapter, cleanup beforehand.
        mListAdapter.removeObserver();
        mListAdapter = new AddFollowsAdapter(this, mButtonRowClickHandler,
                ((PlayLv2) getApplication()).getRemoteResourceManager());

        try {
            // Populate the list control below now.
            if (users != null) {
                mHead.setVisibility(View.VISIBLE);
                mStateHolder.setFriends(users, usersAlpha);
                mBtnAddAllFriends.setVisibility(View.VISIBLE);
                mBtnAddAllFriends.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startProgressBar(getResources().getString(R.string.add_follows_requests_activity_label),
                                getResources().getString(R.string.add_follows_requests_progress_bar_request));
                        // here means all friends
                        mStateHolder.startTaskSendInviteFriend(AddFollowsActivity.this, "0");
                    }
                });
            } else {
                // if no friends, show add friend button
                mBtnAddFriends.setVisibility(View.VISIBLE);
                mBtnAddFriends.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startActivity(new Intent(AddFollowsActivity.this, AddFriendsActivity.class));
                    }
                });
            }
            mListAdapter.setGroup(mStateHolder.getFoundFriendsFiltered());
        } finally {
            getListView().setAdapter(mListAdapter);
            stopProgressBar();
        }
    }

    private void onInviteFriendTaskComplete(Response response, Exception ex) {
        stopProgressBar();
        if (response != null && response.getValue().equals("0")) {
            mListAdapter.setGroup(mStateHolder.getFoundFriendsFiltered());
            mListAdapter.notifyDataSetChanged();
            Toast.makeText(this,
                        getResources().getString(R.string.friend_focused_request_send_ok),
                        Toast.LENGTH_LONG).show();
        }
    }

    private AddFollowsAdapter.ButtonRowClickHandler mButtonRowClickHandler =
        new AddFollowsAdapter.ButtonRowClickHandler() {

        @Override
        public void onBtnClickInvite(User user) {
            inviteFollow(user);
        }

        @Override
        public void onBtnClickInfo(User user) {
            infoFriendOnPlaylv2(user);
        }
    };

    private void inviteFollow(User user) {
        startProgressBar(getResources().getString(R.string.add_follows_requests_activity_label),
                getResources().getString(R.string.add_follows_requests_progress_bar_request));
        mStateHolder.startTaskSendInviteFriend(this, user.getId());
    }

    private void infoFriendOnPlaylv2(User user) {
        Intent intent = new Intent(this, UserDetailsActivity.class);
        intent.putExtra(UserDetailsActivity.EXTRA_USER_PARCEL, user);
        startActivity(intent);
    }

    private static class FriendsOnPlayLv2Task extends AsyncTask<String, Void, Group<User>> {

        private AddFollowsActivity mActivity;
        private HashMap<String, Group<User>> mRequestsAlpha;
        private Exception mReason;

        public FriendsOnPlayLv2Task(AddFollowsActivity activity) {
            mActivity = activity;
            mRequestsAlpha = new LinkedHashMap<String, Group<User>>();
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected Group<User> doInBackground(String... params) {
            try {
                PlayLv2 playlv2 = (PlayLv2) mActivity.getApplication();
                Group<User> requests =  playlv2.getPlayLv2Api().friends(params[0]);
                if (requests != null && !requests.isEmpty())   {
                    for (User it : requests) {
                        String name = it.getUserName();
                        String first = name.substring(0, 1);
                        Group<User> block = mRequestsAlpha.get(first);
                        if (block == null) {
                            block = new Group<User>();
                            mRequestsAlpha.put(first, block);
                        }
                        block.add(it);
                    }
                }
                return requests;
            } catch (Exception ex) {
                mReason = ex;
                return null;
            }
        }

        @Override
        protected void onPostExecute(Group<User> users) {
            if (mActivity != null) {
                mActivity.onFriendsOnPlayLv2TaskComplete(users, mRequestsAlpha, mReason);
            }
        }
    }

    private static class SendInviteFriendTask extends AsyncTask<Void, Void, Response> {

        private AddFollowsActivity mActivity;
        private String mUserId;
        private String mTripId;
        private Exception mReason;

        public SendInviteFriendTask(AddFollowsActivity activity,
                                             String userId,
                                             String tripId) {
            mActivity = activity;
            mUserId = userId;
            mTripId = tripId;
        }

        @Override
        protected Response doInBackground(Void... params) {
            try {
                PlayLv2Api playlv2api = ((PlayLv2) mActivity.getApplication()).getPlayLv2Api();
                Response response = playlv2api.tripFollowedRequest(mTripId, mUserId);
                if (response == null) response = new Response();
                return response;
            } catch (Exception ex) {
                mReason = ex;
                return null;
            }
        }

        @Override
        protected void onPostExecute(Response response) {
            if (mActivity != null) {
                mActivity.onInviteFriendTaskComplete(response, mReason);
            }
        }

        @Override
        protected void onCancelled() {
            if (mActivity != null) {
                mActivity.onInviteFriendTaskComplete(null,
                        new Exception("Invite friend request cancelled."));
            }
        }
    }

    private Runnable mRunnableFilter = new Runnable() {
        public void run() {
            mStateHolder.filterFriendRequests(mNameFilter.getText().toString());
            mListAdapter.setGroup(mStateHolder.getFoundFriendsFiltered());
            mListAdapter.notifyDataSetChanged();
        }
    };

    private static class StateHolder {

        private Group<User> mFriends;
        private Group<User> mFoundFriendsFiltered;
        private FriendsOnPlayLv2Task mTaskFriendsOnPlayLv2;
        private SendInviteFriendTask mTaskSendInvite;
        private String mUserId;
        private String mTripId;

        public StateHolder() {
            mFriends = new Group<User>();
            mFoundFriendsFiltered = null;
        }

        public void setUserId(String userId)    {
            mUserId = userId;
        }

        public void setTripId(String tripId)    {
            mTripId = tripId;
        }

        public Group<User> getFoundFriendsFiltered() {
            if (mFoundFriendsFiltered == null) {
                return mFriends;
            }
            return mFoundFriendsFiltered;
        }

        public void startTaskFriendOnPlayLv2(AddFollowsActivity activity) {
            mTaskFriendsOnPlayLv2 = new FriendsOnPlayLv2Task(activity);
            mTaskFriendsOnPlayLv2.execute(mUserId);
        }

        public void startTaskSendInviteFriend(AddFollowsActivity activity, String userId) {
            mTaskSendInvite = new SendInviteFriendTask( activity, userId, mTripId );
            mTaskSendInvite.execute();
        }

        public void setFriends(Group<User> requests, HashMap<String, Group<User>> alpha) {
            if (requests != null) {
                mFriends = requests;
                mFoundFriendsFiltered = null;
            } else {
                mFriends = new Group<User>();
                mFoundFriendsFiltered = null;
            }
        }

        public void filterFriendRequests(String filterString) {
            // If no filter, just keep using the original found friends group.
            // If a filter is supplied, reconstruct the group using the alpha
            // map so we don't have to go through the entire list.
            mFoundFriendsFiltered = null;
            if (!TextUtils.isEmpty(filterString)) {
                filterString = filterString.toUpperCase();

                mFoundFriendsFiltered = new Group<User>();
                if (mFriends != null) {
                    for (User it : mFriends) {
                        String name = it.getUserName();
                        if (name.startsWith(filterString)) {
                            mFoundFriendsFiltered.add(it);
                        }
                    }
                }
            }
        }
    }
}
